home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / ftp / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-21  |  10.6 KB  |  562 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. char copyright[] =
  35.   "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n"
  36.   "All rights reserved.\n";
  37.  
  38. /*
  39.  * from: @(#)main.c    5.18 (Berkeley) 3/1/91
  40.  */
  41. char main_rcsid[] = 
  42.   "$Id: main.c,v 1.8 1996/07/21 09:28:33 dholland Exp $";
  43.  
  44.  
  45. /*
  46.  * FTP User Program -- Command Interface.
  47.  */
  48. #include <sys/socket.h>
  49. #include <sys/ioctl.h>
  50. #include <sys/types.h>
  51.  
  52. #include <arpa/ftp.h>
  53.  
  54. #include <signal.h>
  55. #include <unistd.h>
  56. #include <string.h>
  57. #include <stdlib.h>
  58. #include <stdio.h>
  59. #include <errno.h>
  60. #include <ctype.h>
  61. #include <netdb.h>
  62. #include <pwd.h>
  63. #ifdef    __USE_READLINE__
  64. #include <readline/readline.h>
  65. #include <readline/history.h>
  66. #endif
  67.  
  68. #define Extern
  69. #include "ftp_var.h"
  70.  
  71. uid_t    getuid(void);
  72. void    intr(int), lostpeer(int);
  73. extern    char *home;
  74. char    *getlogin(void);
  75.  
  76. static void cmdscanner(int top);
  77. void help(int argc, char *argv[]);
  78.  
  79.  
  80. int
  81. main(volatile int argc, char **volatile argv)
  82. {
  83.     register char *cp;
  84.     struct servent *sp;
  85.     int top;
  86.     struct passwd *pw = NULL;
  87.     char homedir[MAXPATHLEN];
  88.  
  89.     tick = 0;
  90.  
  91.     sp = getservbyname("ftp", "tcp");
  92.     if (sp == 0) {
  93.         fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
  94.         exit(1);
  95.     }
  96.     ftp_port = sp->s_port;
  97.     doglob = 1;
  98.     interactive = 1;
  99.     autologin = 1;
  100.     passivemode = 0;
  101.  
  102.         cp = strrchr(argv[0], '/');
  103.         cp = (cp == NULL) ? argv[0] : cp+1;
  104.         if (strcmp(cp, "pftp") == 0)
  105.             passivemode = 1;
  106.  
  107.     argc--, argv++;
  108.     while (argc > 0 && **argv == '-') {
  109.         for (cp = *argv + 1; *cp; cp++)
  110.             switch (*cp) {
  111.  
  112.             case 'd':
  113.                 options |= SO_DEBUG;
  114.                 debug++;
  115.                 break;
  116.             
  117.             case 'v':
  118.                 verbose++;
  119.                 break;
  120.  
  121.             case 't':
  122.                 trace++;
  123.                 break;
  124.  
  125.             case 'i':
  126.                 interactive = 0;
  127.                 break;
  128.  
  129.             case 'n':
  130.                 autologin = 0;
  131.                 break;
  132.  
  133.             case 'p':
  134.                 passivemode = 1;
  135.                 break;
  136.  
  137.             case 'g':
  138.                 doglob = 0;
  139.                 break;
  140.  
  141.             default:
  142.                 fprintf(stdout,
  143.                   "ftp: %c: unknown option\n", *cp);
  144.                 exit(1);
  145.             }
  146.         argc--, argv++;
  147.     }
  148.     fromatty = isatty(fileno(stdin));
  149.     if (fromatty)
  150.         verbose++;
  151.     cpend = 0;    /* no pending replies */
  152.     proxy = 0;    /* proxy not active */
  153.     crflag = 1;    /* strip c.r. on ascii gets */
  154.     sendport = -1;    /* not using ports */
  155.     /*
  156.      * Set up the home directory in case we're globbing.
  157.      */
  158.     cp = getlogin();
  159.     if (cp != NULL) {
  160.         pw = getpwnam(cp);
  161.     }
  162.     if (pw == NULL)
  163.         pw = getpwuid(getuid());
  164.     if (pw != NULL) {
  165.         home = homedir;
  166.         (void) strcpy(home, pw->pw_dir);
  167.     }
  168.     if (argc > 0) {
  169.         if (sigsetjmp(toplevel, 1))
  170.             exit(0);
  171.         (void) signal(SIGINT, intr);
  172.         (void) signal(SIGPIPE, lostpeer);
  173.         setpeer(argc + 1, argv - 1);
  174.     }
  175.     top = sigsetjmp(toplevel, 1) == 0;
  176.     if (top) {
  177.         (void) signal(SIGINT, intr);
  178.         (void) signal(SIGPIPE, lostpeer);
  179.     }
  180.     for (;;) {
  181.         cmdscanner(top);
  182.         top = 1;
  183.     }
  184. }
  185.  
  186. void
  187. intr(int ignore)
  188. {
  189.     siglongjmp(toplevel, 1);
  190. }
  191.  
  192. void
  193. lostpeer(int ignore)
  194. {
  195.     extern FILE *cout;
  196.     extern int data;
  197.  
  198.     if (connected) {
  199.         if (cout != NULL) {
  200.             (void) shutdown(fileno(cout), 1+1);
  201.             (void) fclose(cout);
  202.             cout = NULL;
  203.         }
  204.         if (data >= 0) {
  205.             (void) shutdown(data, 1+1);
  206.             (void) close(data);
  207.             data = -1;
  208.         }
  209.         connected = 0;
  210.     }
  211.     pswitch(1);
  212.     if (connected) {
  213.         if (cout != NULL) {
  214.             (void) shutdown(fileno(cout), 1+1);
  215.             (void) fclose(cout);
  216.             cout = NULL;
  217.         }
  218.         connected = 0;
  219.     }
  220.     proxflag = 0;
  221.     pswitch(0);
  222. }
  223.  
  224. /*char *
  225. tail(filename)
  226.     char *filename;
  227. {
  228.     register char *s;
  229.     
  230.     while (*filename) {
  231.         s = rindex(filename, '/');
  232.         if (s == NULL)
  233.             break;
  234.         if (s[1])
  235.             return (s + 1);
  236.         *s = '\0';
  237.     }
  238.     return (filename);
  239. }
  240. */
  241. /*
  242.  * Command parser.
  243.  */
  244. static void
  245. cmdscanner(int top)
  246. {
  247.     register struct cmd *c;
  248.     register int l;
  249.     struct cmd *getcmd();
  250. #ifdef __USE_READLINE__
  251.     char *lineread;
  252. #endif
  253.  
  254.     if (!top)
  255.         (void) putchar('\n');
  256.     for (;;) {
  257.         if (fromatty) {
  258. #ifdef __USE_READLINE__
  259.             lineread = readline("ftp> ");
  260. #else
  261.             printf("ftp> ");
  262.             (void) fflush(stdout);
  263. #endif
  264.         }
  265. #ifdef __USE_READLINE__
  266.         if (!fromatty) {
  267.             if (fgets(line, sizeof line, stdin) == NULL)
  268.                 quit(0, NULL);
  269.         } else {
  270.             if (!lineread) {
  271.                 quit(0, NULL);
  272.                 break;
  273.             }
  274.             strcpy(line, lineread);
  275.             if (lineread[0]) add_history(lineread);
  276.             free(lineread);
  277.                 }
  278. #else
  279.         if (fgets(line, sizeof line, stdin) == NULL)
  280.             quit(0, NULL);
  281. #endif
  282.         l = strlen(line);
  283.         if (l == 0)
  284.             break;
  285.         if (line[--l] == '\n') {
  286.             if (l == 0)
  287.                 break;
  288.             line[l] = '\0';
  289.         } else if (l == sizeof(line) - 2) {
  290.             printf("sorry, input line too long\n");
  291.             while ((l = getchar()) != '\n' && l != EOF)
  292.                 /* void */;
  293.             break;
  294.         } /* else it was a line without a newline */
  295.         makeargv();
  296.         if (margc == 0) {
  297.             continue;
  298.         }
  299.         c = getcmd(margv[0]);
  300.         if (c == (struct cmd *)-1) {
  301.             printf("?Ambiguous command\n");
  302.             continue;
  303.         }
  304.         if (c == 0) {
  305.             printf("?Invalid command\n");
  306.             continue;
  307.         }
  308.         if (c->c_conn && !connected) {
  309.             printf("Not connected.\n");
  310.             continue;
  311.         }
  312.         (*c->c_handler)(margc, margv);
  313.         if (bell && c->c_bell)
  314.             (void) putchar('\007');
  315.         if (c->c_handler != help)
  316.             break;
  317.     }
  318.     (void) signal(SIGINT, intr);
  319.     (void) signal(SIGPIPE, lostpeer);
  320. }
  321.  
  322. struct cmd *
  323. getcmd(name)
  324.     register char *name;
  325. {
  326.     extern struct cmd cmdtab[];
  327.     register char *p, *q;
  328.     register struct cmd *c, *found;
  329.     register int nmatches, longest;
  330.  
  331.     longest = 0;
  332.     nmatches = 0;
  333.     found = 0;
  334.     for (c = cmdtab; (p = c->c_name) != NULL; c++) {
  335.         for (q = name; *q == *p++; q++)
  336.             if (*q == 0)        /* exact match? */
  337.                 return (c);
  338.         if (!*q) {            /* the name was a prefix */
  339.             if (q - name > longest) {
  340.                 longest = q - name;
  341.                 nmatches = 1;
  342.                 found = c;
  343.             } else if (q - name == longest)
  344.                 nmatches++;
  345.         }
  346.     }
  347.     if (nmatches > 1)
  348.         return ((struct cmd *)-1);
  349.     return (found);
  350. }
  351.  
  352. /*
  353.  * Slice a string up into argc/argv.
  354.  */
  355.  
  356. int slrflag;
  357.  
  358. void
  359. makeargv(void)
  360. {
  361.     char **argp;
  362.     char *slurpstring();
  363.  
  364.     margc = 0;
  365.     argp = margv;
  366.     stringbase = line;        /* scan from first of buffer */
  367.     argbase = argbuf;        /* store from first of buffer */
  368.     slrflag = 0;
  369.     while ((*argp++ = slurpstring())!=NULL)
  370.         margc++;
  371. }
  372.  
  373. /*
  374.  * Parse string into argbuf;
  375.  * implemented with FSM to
  376.  * handle quoting and strings
  377.  */
  378. char *
  379. slurpstring()
  380. {
  381.     int got_one = 0;
  382.     register char *sb = stringbase;
  383.     register char *ap = argbase;
  384.     char *tmp = argbase;        /* will return this if token found */
  385.  
  386.     if (*sb == '!' || *sb == '$') {    /* recognize ! as a token for shell */
  387.         switch (slrflag) {    /* and $ as token for macro invoke */
  388.             case 0:
  389.                 slrflag++;
  390.                 stringbase++;
  391.                 return ((*sb == '!') ? "!" : "$");
  392.                 /* NOTREACHED */
  393.             case 1:
  394.                 slrflag++;
  395.                 altarg = stringbase;
  396.                 break;
  397.             default:
  398.                 break;
  399.         }
  400.     }
  401.  
  402. S0:
  403.     switch (*sb) {
  404.  
  405.     case '\0':
  406.         goto OUT;
  407.  
  408.     case ' ':
  409.     case '\t':
  410.         sb++; goto S0;
  411.  
  412.     default:
  413.         switch (slrflag) {
  414.             case 0:
  415.                 slrflag++;
  416.                 break;
  417.             case 1:
  418.                 slrflag++;
  419.                 altarg = sb;
  420.                 break;
  421.             default:
  422.                 break;
  423.         }
  424.         goto S1;
  425.     }
  426.  
  427. S1:
  428.     switch (*sb) {
  429.  
  430.     case ' ':
  431.     case '\t':
  432.     case '\0':
  433.         goto OUT;    /* end of token */
  434.  
  435.     case '\\':
  436.         sb++; goto S2;    /* slurp next character */
  437.  
  438.     case '"':
  439.         sb++; goto S3;    /* slurp quoted string */
  440.  
  441.     default:
  442.         *ap++ = *sb++;    /* add character to token */
  443.         got_one = 1;
  444.         goto S1;
  445.     }
  446.  
  447. S2:
  448.     switch (*sb) {
  449.  
  450.     case '\0':
  451.         goto OUT;
  452.  
  453.     default:
  454.         *ap++ = *sb++;
  455.         got_one = 1;
  456.         goto S1;
  457.     }
  458.  
  459. S3:
  460.     switch (*sb) {
  461.  
  462.     case '\0':
  463.         goto OUT;
  464.  
  465.     case '"':
  466.         sb++; goto S1;
  467.  
  468.     default:
  469.         *ap++ = *sb++;
  470.         got_one = 1;
  471.         goto S3;
  472.     }
  473.  
  474. OUT:
  475.     if (got_one)
  476.         *ap++ = '\0';
  477.     argbase = ap;            /* update storage pointer */
  478.     stringbase = sb;        /* update scan pointer */
  479.     if (got_one) {
  480.         return(tmp);
  481.     }
  482.     switch (slrflag) {
  483.         case 0:
  484.             slrflag++;
  485.             break;
  486.         case 1:
  487.             slrflag++;
  488.             altarg = (char *) 0;
  489.             break;
  490.         default:
  491.             break;
  492.     }
  493.     return((char *)0);
  494. }
  495.  
  496. #define HELPINDENT (sizeof ("directory"))
  497.  
  498. /*
  499.  * Help command.
  500.  * Call each command handler with argc == 0 and argv[0] == name.
  501.  */
  502. void
  503. help(int argc, char *argv[])
  504. {
  505.     extern struct cmd cmdtab[];
  506.     register struct cmd *c;
  507.  
  508.     if (argc == 1) {
  509.         register int i, j, w, k;
  510.         int columns, width = 0, lines;
  511.         extern int NCMDS;
  512.  
  513.         printf("Commands may be abbreviated.  Commands are:\n\n");
  514.         for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
  515.             int len = strlen(c->c_name);
  516.  
  517.             if (len > width)
  518.                 width = len;
  519.         }
  520.         width = (width + 8) &~ 7;
  521.         columns = 80 / width;
  522.         if (columns == 0)
  523.             columns = 1;
  524.         lines = (NCMDS + columns - 1) / columns;
  525.         for (i = 0; i < lines; i++) {
  526.             for (j = 0; j < columns; j++) {
  527.                 c = cmdtab + j * lines + i;
  528.                 if (c->c_name && (!proxy || c->c_proxy)) {
  529.                     printf("%s", c->c_name);
  530.                 }
  531.                 else if (c->c_name) {
  532.                     for (k=0; k < strlen(c->c_name); k++) {
  533.                         (void) putchar(' ');
  534.                     }
  535.                 }
  536.                 if (c + lines >= &cmdtab[NCMDS]) {
  537.                     printf("\n");
  538.                     break;
  539.                 }
  540.                 w = strlen(c->c_name);
  541.                 while (w < width) {
  542.                     w = (w + 8) &~ 7;
  543.                     (void) putchar('\t');
  544.                 }
  545.             }
  546.         }
  547.         return;
  548.     }
  549.     while (--argc > 0) {
  550.         register char *arg;
  551.         arg = *++argv;
  552.         c = getcmd(arg);
  553.         if (c == (struct cmd *)-1)
  554.             printf("?Ambiguous help command %s\n", arg);
  555.         else if (c == (struct cmd *)0)
  556.             printf("?Invalid help command %s\n", arg);
  557.         else
  558.             printf("%-*s\t%s\n", HELPINDENT,
  559.                 c->c_name, c->c_help);
  560.     }
  561. }
  562.